package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.service.CartInfoAsyncService;
import com.atguigu.gmall.cart.service.CartInfoService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.AuthContextHolder;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import sun.text.CollatorUtilities;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 购物车表 用户登录系统时更新冗余(CartInfo)表服务实现类
 *
 * @author makejava
 * @since 2021-04-16 19:14:18
 */
@Service("cartInfoService")
public class CartInfoServiceImpl implements CartInfoService {

    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private CartInfoAsyncService cartInfoAsyncService;
    @Resource
    private ProductFeignClient productFeignClient;

    @Override
    public CartInfo addCart(Long skuId, Integer skuNum) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String userId = AuthContextHolder.getUserId(request);
        //获取真实用户ID
        if(StringUtils.isEmpty(userId)){
            //临时用户ID
            userId = AuthContextHolder.getUserTempId(request);
        }
        // Hash类型  散列类型
        // 参数1： h   Map h = new HashMap();  用户ID   user:3:cart
        // 参数2： hk   h.put(k,               skuId
        // 参数3： hv   h.put(k,v)             CartInfo
        String cacheH = getCacheH(userId);
        String cacheHK = skuId.toString();
        //1、缓存中查询购物车内是否有该商品     先修改缓存，后异步更新数据库
        CartInfo cartInfo = (CartInfo)redisTemplate.opsForHash().get(cacheH,cacheHK);
        if (cartInfo != null){
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);//增加数量
            cartInfo.setIsChecked(CartInfo.ISCHECKED);//选中
            cartInfoAsyncService.update(cartInfo);
        }else {
            cartInfo = new CartInfo();
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            cartInfo.setCartPrice(skuInfo.getPrice());
            cartInfo.setSkuNum(skuNum);
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setSkuPrice(skuInfo.getPrice());
            cartInfoAsyncService.insert(cartInfo);
        }
        //保存缓存
        redisTemplate.opsForHash().put(cacheH,cacheHK,cartInfo);
        return cartInfo;
    }

    @Override
    public CartInfo toCart(Long skuId) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();

        String userId = AuthContextHolder.getUserId(request);
        if(StringUtils.isEmpty(userId)){
            //临时用户ID
            userId = AuthContextHolder.getUserTempId(request);
        }
        String cacheH = getCacheH(userId);
        String cacheHK = skuId.toString();
        return (CartInfo)redisTemplate.opsForHash().get(cacheH,cacheHK);
    }

    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
        //判断当前用户情况
        //1、有真实用户
        if (!StringUtils.isEmpty(userId)){
            //1.1、有临时用户     合并：加购物车 or 加数量
            if (!StringUtils.isEmpty(userTempId)){
                return mergeCartList(userId,userTempId);
            }
            //1.2、无临时用户     返回真实用户购物车列表
            else {
                return getCartList(userId);
            }
        }
        //2、无真实用户
        else {
            //2.1、有临时用户     登录后会建立真实用户，成为两种存在的情况
            if (!StringUtils.isEmpty(userTempId)){
                return getCartList(userTempId);
            }
        }
        //2.2、无临时用户     其余情况已在判断中return，可在最外层返回null
        return null;
    }

    @Override
    public void checkCart(Long skuId, Integer isChecked) {
        //获取用户id
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String userId = AuthContextHolder.getUserId(request);
        if (StringUtils.isEmpty(userId)){
            userId = AuthContextHolder.getUserTempId(request);
        }
        //更新redis
        String cacheH = getCacheH(userId);
        CartInfo cartInfo = (CartInfo)redisTemplate.opsForHash().get(cacheH, skuId.toString());
        cartInfo.setIsChecked(isChecked);
        redisTemplate.opsForHash().put(cacheH,skuId.toString(),cartInfo);
        //更新DB
        cartInfoAsyncService.update(cartInfo);
    }

    @Override
    public List<CartInfo> getCartListCecked(String userId) {
        //该用户购物车内所有商品
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(getCacheH(userId));
        //实时价格      注：添加canal后不需要写实时价格

        //过滤每条中符合isChecked==1条件的对象
        return cartInfoList.stream().filter(cartInfo -> cartInfo.getIsChecked() == 1).collect(Collectors.toList());
    }

    //合并购物车
    private List<CartInfo> mergeCartList(String userId, String userTempId) {
        //获取真实用户购物车集合
        List<CartInfo> userCartList = getCartList(userId);
        //获取临时用户购物车集合
        List<CartInfo> tempUserCartList = getCartList(userTempId);
        //1、真实用户购物车存在
        if (!CollectionUtils.isEmpty(userCartList)){
            //1.1、临时用户购物车存在
            if (!CollectionUtils.isEmpty(tempUserCartList)){
                //取出真实购物车id集合
                Map<Long,CartInfo> cartInfoMap = userCartList.stream().collect(Collectors
                        .toMap(CartInfo::getSkuId, cartInfo -> cartInfo));
                tempUserCartList.stream().forEach(tempUserCart->{
                    //真实购物车id集合中获取临时id对应的value值     获取的v为对象，可不回put，string类型需put
                    CartInfo cartInfo = cartInfoMap.get(tempUserCart.getSkuId());
                    //1、具有相同商品，添加数量,设置选中
                    if (cartInfo != null){
                        cartInfo.setSkuNum(cartInfo.getSkuNum()+tempUserCart.getSkuNum());
                        cartInfo.setIsChecked(CartInfo.ISCHECKED);
                        //更新redis
                        redisTemplate.opsForHash().put(getCacheH(userId),cartInfo.getSkuId().toString(),cartInfo);
                        //更新DB
                        cartInfoAsyncService.update(cartInfo);
                    }
                    //2、没有商品，添加商品
                    else {
                        //添加redis
                        tempUserCart.setUserId(userId);
                        redisTemplate.opsForHash().put(getCacheH(userId),tempUserCart.getSkuId().toString(),tempUserCart);
                        //添加DB
                        cartInfoAsyncService.insert(tempUserCart);
                        cartInfoMap.put(tempUserCart.getSkuId(),tempUserCart);
                    }
                });
                //删除临时id购物车
                redisTemplate.delete(getCacheH(userTempId));
                cartInfoAsyncService.delete(userTempId);
                return new ArrayList<>(cartInfoMap.values());
            }
            //1.2、临时用户购物车不存在
            else {
                return userCartList;
            }
        }
        //2、真实用户购物车不存在
        else {
            //2.1、临时用户购物车存在     仅修改用户id
            if (!CollectionUtils.isEmpty(tempUserCartList)){
                Map<String,CartInfo> cartInfoMap = tempUserCartList.stream().map(tempUserCart->{
                    //修改每条临时购物车用户id为真实用户id
                    tempUserCart.setUserId(userId);
                    return tempUserCart;
                }).collect(     //CartInfo中的getSkuId方法  cartInfo并返回cartInfo
                        Collectors.toMap(cartInfo -> cartInfo.getSkuId().toString(),cartInfo -> cartInfo));

                //更新缓存
                String cacheHId = getCacheH(userId);
                redisTemplate.opsForHash().putAll(cacheHId,cartInfoMap);
                //删除旧缓存
                String cacheHTempId = getCacheH(userTempId);
                redisTemplate.delete(cacheHTempId);
                //异步更新DB
                cartInfoAsyncService.updateByIdAsyncId(userTempId,userId);
                return tempUserCartList;
            }
        }
        //2.2、临时用户购物车不存在
        return null;
    }

    private List<CartInfo> getCartList(String userId) {
        //当前获取购物车列表，未涉及修改数据库
        //redis中保存hash无序，需根据添加顺序进行排序
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(getCacheH(userId));
        //数据库查询实时价格
        cartInfoList.forEach(cartInfo -> {
            cartInfo.setSkuPrice(productFeignClient.getPrice(cartInfo.getSkuId()));
        });

        return cartInfoList.stream().sorted((o1,o2)->
            o2.getSkuNum()-o1.getSkuNum()
        ).collect(Collectors.toList());
    }


    private String getCacheH(String userId){
        return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    }
}

